package com.sokobanboxpro.game.gameplay;

import com.sokobanboxpro.game.entity.*;
import java.util.ArrayList;
import java.util.Stack;
import org.newdawn.slick.GameContainer;

/**
 * То, что происходит в игре. Содержит игровую логику
 *
 * @author Esr
 */
public class Gameplay {

		/**
		 * Камера игры
		 */
		private final Camera camera = new Camera(0, 0);
		/**
		 * Игра, к которой принадлежит геймплей
		 */
		private Game game;
		private Stack<Move> moves = new Stack<Move>();

		/**
		 * Создание геймплея
		 *
		 * @param game Игра, к которой принадлежит геймплей
		 */
		public void init(Game game) {
				this.game = game;
		}

		/**
		 * Обновление геймплея
		 *
		 * @param gc
		 * @param delta Время прошедшее с предыдушего обновления
		 */
		public void update(GameContainer gc, int delta) {
		}

		/**
		 * Нажатие мыши или касание экрана
		 *
		 * @param x Координата x
		 * @param y Координата y
		 */
		public void mousePressed(int x, int y) {
		}

		/**
		 * Перемешение мыши или пальца
		 *
		 * @param oldx Начальная координата x
		 * @param oldy Начальная координата y
		 * @param newx Новая координата x
		 * @param newy Новая координата y
		 */
		public void mouseDragged(int oldx, int oldy, int newx, int newy) {
		}

		/**
		 * Получить камеру
		 *
		 * @return Камера
		 */
		public Camera getCamera() {
				return camera;
		}

		/**
		 * Сместить игрока.
		 * @param deltaX Смешение по x
		 * @param deltaY Смешение по y
		 */
		private void movePlayer(int deltaX, int deltaY) {

				int x = game.getCurrentLevel().getPlayer().getX();
				int y = game.getCurrentLevel().getPlayer().getY();
				Move move = new Move();

				Level level = game.getCurrentLevel();
				Wall wall = level.findWallAtPosition(x + deltaX, y + deltaY);
				if (wall != null) {
						return;
				}
				Box box = level.findBoxAtPosition(x + deltaX, y + deltaY);
				if (box != null) {
						Wall wallBehindBox = level.findWallAtPosition(x + deltaX * 2, y + deltaY * 2);
						Box boxBehidnBOx = level.findBoxAtPosition(x + deltaX * 2, y + deltaY * 2);
						if (wallBehindBox != null || boxBehidnBOx != null) {
								return;
						}

						move.setBoxMove(true);
						move.setBoxX(box.getX());
						move.setBoxY(box.getY());
						move.setBox(box);

						box.changeX(deltaX);
						box.changeY(deltaY);

				} else {
						move.setBoxMove(false);
				}

				move.setPlayerX(game.getCurrentLevel().getPlayer().getX());
				move.setPlayerY(game.getCurrentLevel().getPlayer().getY());
				move.setPlayerDirection(game.getCurrentLevel().getPlayer().getDirection());

				game.getCurrentLevel().getPlayer().changeX(deltaX);
				game.getCurrentLevel().getPlayer().changeY(deltaY);

				moves.push(move);

		}

		/**
		 * Переместить игрока на 1 клетку вверх
		 */
		public void movePlayerUp() {

				movePlayer(0, -1);
				game.getCurrentLevel().getPlayer().setDirection(Direction.UP);
				if (isLevelComplited()) {

						game.levelComlited();

				}

		}

		/**
		 * Переместить игрока на 1 клетку вниз
		 */
		public void movePlayerDown() {

				movePlayer(0, 1);
				game.getCurrentLevel().getPlayer().setDirection(Direction.DOWN);
				if (isLevelComplited()) {

						game.levelComlited();

				}

		}

		/**
		 * Переместить игрока на 1 клетку вправо
		 */
		public void movePlayerRight() {

				movePlayer(1, 0);
				game.getCurrentLevel().getPlayer().setDirection(Direction.RIGHT);
				if (isLevelComplited()) {

						game.levelComlited();

				}

		}

		/**
		 * Переместить игрока на 1 клетку влево
		 */
		public void movePlayerLeft() {

				movePlayer(-1, 0);
				game.getCurrentLevel().getPlayer().setDirection(Direction.LEFT);
				if (isLevelComplited()) {

						game.levelComlited();

				}

		}

		/**
		 * Проверка, пройден ли уровень
		 * @return Пройден ли уровень
		 */
		private boolean isLevelComplited() {
				Box[] boxes = game.getCurrentLevel().getBoxes();

				for (Box box : boxes) {
						Point point = game.getCurrentLevel().findPointAtPosition(box.getX(), box.getY());
						if (point == null) {
								return false;
						}

				}

				return true;

		}

		/**
		 * Отменить последний ход
		 */
		public void cancelMove() {

				if (!moves.empty()) {
						Move move = moves.pop();

						game.getCurrentLevel().getPlayer().setX(move.getPlayerX());
						game.getCurrentLevel().getPlayer().setY(move.getPlayerY());
						game.getCurrentLevel().getPlayer().setDirection(move.getPlayerDirection());

						if (move.isBoxMove()) {
								move.getBox().setX(move.getBoxX());
								move.getBox().setY(move.getBoxY());
						}
				}
		}

		/**
		 * Вызывается, когда уровень был пройден
		 */
		public void levelChanged() {

				moves.clear();

		}

}
